home *** CD-ROM | disk | FTP | other *** search
- Subject: v14i085: 3B2 Ethernet Connection and File Transfer Utility
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Dave Settle <mcvax!oscar.smb.co.uk!dave@uunet.uu.net>
- Posting-number: Volume 14, Issue 85
- Archive-name: 3bconnect
-
- [ I don't have a 3B, so you're on your own. --r$ ]
-
- This set is called 'connect', and is a utility for AT&T 3B2
- 3BNET (ethernet) networks, providing a remote login facility, and a
- file transfer capability.
-
- Dave.
- -----------------------------------CUT HERE-----------------------------------
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # README
- # Makefile
- # connect.1
- # rcp.1
- # server.c
- # connect.c
- # rcp.c
- # eth.c
- # ipaddr.c
- # talk.c
- # sub.c
- # file.c
- # terminate.c
- # mynode.c
- # ftp.c
- # ni.h
- # ftp.h
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'README'" '(4159 characters)'
- if test -f 'README'
- then
- echo shar: "will not over-write existing file 'README'"
- else
- cat << \SHAR_EOF > 'README'
- AT&T 3B2 Ethernet Connection and File Transfer Utility
-
- This package allows you to login to other 3B2 computers connected via 3Bnet,
- in a similar fashion to 'cu', and also to transfer files across the ethernet.
-
- CONNECT
-
- 'Connect' provides a simple connection to a shell on the remote machine, linked
- to your terminal via pipes. Initially, YOUR terminal will be doing the echoing
- (in contrast to 'cu'), with lines shipped across the ethernet only when you
- hit RETURN.
-
- You can force the connection into 'raw' mode (each character shipped as typed,
- remote end doing the echoing) by sending a QUIT signal. This allows you to
- use screen editors on the remote machine.
- A further QUIT signal gets you back into 'cooked' mode - this is indicated by
- '[cooked]' appearing on your terminal. Unfortunately, this means that you
- can't send QUIT signals to processes which you start on the remote host.
- Sorry about this. Interrupts get processed OK, though.
-
- You close the connection by typing ^D at your terminal (in cooked mode) -
- if you want to send ^D to the remote end, you MUST be in 'raw' mode.
-
- The big problem is that your remote shell has stdin, stdout, and stderr
- connected to PIPES, rather than a real tty, which can cause certain commands
- (e.g. stty) to fail.
-
- PC-INTERFACE.
- If you have PC-INTERFACE installed, then you can connect to one of the
- pseudo-tty devices provided by the driver, by using the '-l' option of 'connect'
- This gets you a remote shell connected to a 'real' tty device, and
- automatically puts you in 'raw' mode.
-
- You close this type of connection by sending a QUIT signal.
-
-
- RCP
- 'rcp' provides a simple, but effective, method of transferring files across
- the network. The syntax resembles 'uucp'.
-
-
-
- WHAT YOU NEED TO DO TO INSTALL IT.
-
- a) Find out the ethernet addresses of all machines on the network.
- Use 'nitable', or the program 'mynode' provided.
-
- b) Set up a map file '/usr/lib/ethernet.addr' which maps the names of
- your hosts to the rightmost 2 digits of their ethernet address.
- These should be unique - if not, change the value of LSB in 'ni.h'
- to use any pair of digits which are unique for your network.
-
-
- E.g.
- oscar 80.00.10.30.18.f2
- olive 80.00.10.30.0b.45
-
- /usr/lib/ethernet.addr:
-
- oscar f2
- olive 45
-
-
- c) Set up an inittab entry to run the server.
-
- e.g. (assuming server is '/usr/lib/server')
-
- et:2:respawn:/usr/lib/server
-
- It's important that this line is properly defined!
- DO NOT DEFINE ANY INPUT OR OUTPUT FILES FOR THIS PROCESS.
-
-
- d) Make sure that you have enough 'port' structures allocated in the NI driver.
- You can do this through the 'packagemgmt/3bnet/nidriver" option in 'sysadm'
- I have 20 ports, 1 buffer per port, 1514 buffer size - this allows
- me at least 5 concurrent 'connects' (I've not tried more)
- You have to reboot for the reconfig to become effective.
-
- e) Find out your value of NPROC, from the file /etc/master.d/KERNEL
- Define this value in 'ni.h'
-
-
- f) To connect, say 'connect <host>'
-
- e.g.
- connect olive
-
-
-
- BUGS
-
- TTY:
- You're not connected to a tty at the remote end, so certain commands aren't
- going to work. Screen editors will work, but only if you use them when you're
- in 'raw' mode.
-
- EOT:
- There's no way to send EOT to a remote process. Typing ^D on your terminal will
- close the connection. However, when you do a close, all your remote processes
- get sent a hangup signal, which usually amounts to the same thing.
-
- ETHERNET ADDRESS:
- The ethernet addresses which are used by this package are NOT guaranteed to
- be unique, and may interfere with other ethernet applications. (3Bnet and
- PC-Interface seem to be OK, though).
-
- If you get conflicts with other packages, you might have to change the values
- in server[] and client[] in 'ni.h' ([1] and [2])
-
- They are currently set to 0x02 0x02 - this is totally arbitrary,
- so feel free to change it as you wish.
- The rest of the bytes in server[] and client[] will be OK.
-
- REMOTE SHELL TERMINATION:
- If the remote shell dies, for any reason, you won't be informed until you
- attempt to send it some input.
-
- ADDING FEATURES.
- If you put any fancy bits in, please let me know!
-
- Good luck!
-
- Dave Settle, dave@smb.co.uk
- SHAR_EOF
- if test 4159 -ne "`wc -c < 'README'`"
- then
- echo shar: "error transmitting 'README'" '(should have been 4159 characters)'
- fi
- fi
- echo shar: "extracting 'Makefile'" '(1042 characters)'
- if test -f 'Makefile'
- then
- echo shar: "will not over-write existing file 'Makefile'"
- else
- cat << \SHAR_EOF > 'Makefile'
- #CFLAGS = -g
- #LIBS = -lg
- #
- # If you wish a SECURE version (no super-user server processes),
- # define SECURE. This will prevent root from using 'connect' or 'rcp'.
- #
- # CFLAGS = -O -DSECURE
-
- SERVER = server.o eth.o ipaddr.o talk.o sub.o file.o ftp.o
- CONNECT = connect.o eth.o terminate.o ipaddr.o
- MYNODE = mynode.o ipaddr.o
- RCP = rcp.o sub.o ipaddr.o eth.o ftp.o
-
- DOCS = README Makefile connect.1 rcp.1
-
- SOURCES = server.c connect.c rcp.c eth.c ipaddr.c talk.c \
- sub.c file.c terminate.c mynode.c ftp.c ni.h ftp.h
-
- all: server connect mynode rcp
-
- lint:
- lint ${SERVER:.o=.c}
- lint ${CONNECT:.o=.c}
- lint ${RCP:.o=.c}
-
- ${SERVER} ${CONNECT} ${RCP} : ni.h
-
- rcp.o ftp.o file.o : ftp.h
-
- server: ${SERVER}
- cc -o server ${SERVER} ${LIBS}
-
- connect: ${CONNECT}
- cc -o connect ${CONNECT} ${LIBS}
-
- rcp: ${RCP}
- cc -o rcp ${RCP} ${LIBS}
-
- mynode: ${MYNODE}
- cc -o mynode ${MYNODE} ${LIBS}
-
- shar:
- shar -cv ${DOCS} ${SOURCES} > connect.shar
-
- install:
- if [ -f /usr/lib/server ] ; then \
- mv /usr/lib/server /usr/lib/server.old ; fi
- cp server /usr/lib
- SHAR_EOF
- if test 1042 -ne "`wc -c < 'Makefile'`"
- then
- echo shar: "error transmitting 'Makefile'" '(should have been 1042 characters)'
- fi
- fi
- echo shar: "extracting 'connect.1'" '(3547 characters)'
- if test -f 'connect.1'
- then
- echo shar: "will not over-write existing file 'connect.1'"
- else
- cat << \SHAR_EOF > 'connect.1'
- .TH CONNECT 1 local
- .SH NAME
- connect
- .SH SYNOPSIS
- .B "connect [-l] remote_host"
- .PP
- .SH DESCRIPTION
- .I connect
- allows you to connect to a remote host connected via 3BNET, and to start a
- remote shell on that machine. The shell started is the one specified by
- your SHELL variable, or "/bin/sh" if this is not set.
- .PP
- Initially, all the echoing is done by the local machine, and input is
- transmitted line by line (cooked mode). If you wish the remote machine to
- do the echoing (e.g. you're running a screen editor there), you must put
- your terminal in raw mode, by sending a QUIT signal.
- .PP
- In raw mode, each character is send as soon as it is typed, and no echoing
- is performed by the local machine. A further QUIT signal will revert to
- cooked mode again (i.e. QUIT can be used to toggle between raw and cooked modes)
- .PP
- The connection can be closed by typing EOT in cooked mode.
- .PP
- .SH "LOGIN OPTION"
- .PP
- If the \fB-l\fR option is specified, and if PC-INTERFACE is installed on the
- remote host, then you will be connected to one of the pseudo-ttys supported
- by driver.
- .PP
- This option gives you a remote connection which looks more like a direct
- tty link, and automatically puts you in 'raw' mode.
- .PP
- On the other hand, you have to go through all the bother of logging on,
- which takes more time.
- .PP
- Using the \fB-i\fR option \fBonly\fR, the connection is closed by a QUIT
- signal.
- .SH SECURITY
- The remote server will only accept a request to start a shell if your login
- name is known on the remote machine, and your remote uid matches your local uid.
- .PP
- The uid used to start the remote process is your \fBreal\fR uid, not your
- effective uid, so that even if you're running su(1), your remote process
- will not be root.
- .PP
- The only way you can login to a remote machine as root, is to login to your
- local machine as root (on the console), and \fIconnect\fR from there.
- .PP
- When the remote process it started, it will have your uid, the gid assosciated
- with the \fBremote\fR uid, and will be located in your remote home directory.
- .SH "HOST MAPPING"
- The mapping between host names and ethernet addresses is defined in the
- file '/usr/lib/ethernet.addr'.
- .PP
- The format of the file is:
- .PP
- <hostname> <ID>
- .PP
- e.g.
- .PP
- olive 45
- oscar f2
- .PP
- As shipped, the package expects each host to have a physical ethernet
- address which is unique \fBin the last (lsb) byte\fR.
- .PP
- The addresses which are used are:
- .PP
- XX.YY.YY.00.00.HH Server
- XX.YY.YY.PID.PID.HH Client/Remote Process.
- .PP
- The values of XX and YY are totally arbitrary, and you can change them if
- you wish. The value of HH must be different for each host, and is taken from
- the LSB of the host physical ethernet address. If this does not produce
- a unique value for each server, then you can choose to take it from any other
- byte of the physical address, by redefining LSB (ni.h) to pick any other byte.
- .SH EXAMPLES
- .PP
- connect -l olive
- .PP
- Connect to a PC-INTERFACE pseudo-tty on host 'olive'.
- .PP
- connect oscar
- .PP
- Connect to a remote shell on host 'oscar'
- .PP
- .SH FILES
- /dev/ni Ethernet interface.
- .PP
- /dev/ptty?? PC-INTERFACE pseudo-ttys
- .PP
- /usr/lib/ethernet.add List of hosts.
- .PP
- .SH SEE ALSO
- .SH BUGS
- You can't send QUIT signals to remote processes, 'cos QUIT does various things
- to the connection.
- .PP
- The values of XX and YY may conflict with other applications.
- .PP
- There's no guarantee that you can get a unique host ID using only one byte
- from the physical node address.
- .PP
- \fIconnect <host>\fR gets you a shell which isn't connected to a real tty
- device.
- SHAR_EOF
- if test 3547 -ne "`wc -c < 'connect.1'`"
- then
- echo shar: "error transmitting 'connect.1'" '(should have been 3547 characters)'
- fi
- fi
- echo shar: "extracting 'rcp.1'" '(2176 characters)'
- if test -f 'rcp.1'
- then
- echo shar: "will not over-write existing file 'rcp.1'"
- else
- cat << \SHAR_EOF > 'rcp.1'
- .TH RCP 1 local
- .SH SYNOPSIS
- .B "rcp [-d] source [source ...] dest"
- .SH DESCRIPTION
- \fIrcp\fR allows files to be transferred to or from remote machines,
- using the ethernet connection between Olivetti 3B2's supporting 3BNET.
- It does \fBNOT\fR use the \fInisend\fB network interface, which has
- proved to be very unreliable, but uses the packet transport interface
- directly.
- .PP
- Any of the file names specified may be prefixed with a \fBsystem name\fR,
- meaning that the file should be transferred to or from the remote machine
- specified. The system name is separated from the file name by either
- a '!' or a ':' character.
- .PP
- Only one remote system may be specified for each \fIrcp\fR command,
- and all the source files must live on the same system. It is not possible
- to move files from one place to another on a remote machine - they
- must transfer across the ethernet connection. This is a restriction
- imposed by the protocol.
- .SH FLAGS
- .PP
- .TP
- .B -d
- Turn debugging output on during the file transfer procedure. Useful only
- if you know what the ftp protocol is supposed to be doing.
- .PP
- .SH EXAMPLES
- .PP
- rcp oscar!/usr/dave/file.c /usr/tmp
- .PP
- Copies the file \fB/usr/dave/file.c\fR from the system \fBoscar\fR to the
- destination \fB/usr/tmp\fR on the local system.
- .PP
- rcp /usr/dave/src/rcp.c myprog olive:/usr/dave/public
- .PP
- Copies the local files \fB/usr/dave/src/rcp.c\fR and
- \fBmyprog\fR, to the destination \fB/usr/dave/public\fR on the
- system \fBolive\fR.
- .SH "SEE ALSO"
- uucp(1), cp(1), nisend(1)
- .SH DIAGNOSTICS
- Normal information about files which can't be read or written; this
- information may come from either host.
- .PP
- In the event of a protocol failure, the remote server may terminate
- \fIrcp\fR. There should be a diagnostic message - consult your guru.
- .SH BUGS
- You can't talk to more than one remote host at a time: things like
- .PP
- rcp a:file1 b:file2 c:dest
- .PP
- are \fBNOT\fR allowed.
- .PP
- You can't move things around on the remote host - you can only copy
- from one host to another.
- .PP
- The file transfer protocol is a home-grown variety, and is not going
- to be any sort of standard. It would be nice if it used TCP/IP, or
- some other well-defined protocol.
- SHAR_EOF
- if test 2176 -ne "`wc -c < 'rcp.1'`"
- then
- echo shar: "error transmitting 'rcp.1'" '(should have been 2176 characters)'
- fi
- fi
- echo shar: "extracting 'server.c'" '(6188 characters)'
- if test -f 'server.c'
- then
- echo shar: "will not over-write existing file 'server.c'"
- else
- cat << \SHAR_EOF > 'server.c'
- /*
- * Copyright (C) 1988 Dave Settle. All rights reserved.
- * Permission is granted to use, copy and modify this software, providing
- * that it is not sold for profit, and that this copyright notice is retained
- * in any copies of the source.
- */
- /*
- * server: ethernet server. Accepts requests, and spawns processes to
- * serve remote clients.
- */
-
- #include <sys/ni.h>
- #include <stdio.h>
- #include <sys/signal.h>
- #include <sys/errno.h>
- extern int errno;
- #include <pwd.h>
-
- struct passwd *getpwnam();
- char *strrchr();
-
- #define MAIN
- #include "ni.h"
-
- int input[2], output[2]; /* pipes for shell */
- char cmd[128], program[32];
- int reader, sh; /* pid of child reader process */
-
- #define LOG "/usr/lib/server.log"
-
- #define GIGABYTE 2*1024*1024 /* number of blocks in 1 GByte */
-
- /*
- * endproc: called when the shell has died (via SIGPIPE) by the writer process
- */
- endproc(){
- struct request req;
- skill(reader, SIGTERM);
- sprintf(req.r_data, "your shell died");
- send(&req, strlen(req.r_data), TERMINATE, client);
- exit(0);
- }
- /*
- * Called when we get a TERMINATE packet from the client.
- */
- sigterm(){
- skill(reader, SIGTERM);
- skill(sh, SIGHUP);
- sleep(1);
- skill(sh, SIGKILL);
- exit(0);
- }
-
- main()
- {
- int in;
- signal(SIGHUP, SIG_IGN);
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGTERM, sigterm);
- ulimit(2, (long) GIGABYTE);
- /*
- * This process runs from "init" - it doesn't have ANY file descriptors open
- * Check this, and if necessary, create some dummy fd's.
- */
- if(in = open("/dev/null", 0) == 0) {
- open("/dev/null", 1);
- open("/dev/null", 1);
- }
- else close(in);
- freopen(LOG, "a+", stderr);
- if(configure(server, 2, 0) == -1) exit(1);
- accept();
- return(0);
- }
- accept(){
- struct request request;
- recv(&request);
- /*
- * Fork off child to deal with the request. We die, and are respawned by
- * init.
- */
- if(fork() == 0) exit(serve(&request));
- /*
- * parent - exit.
- */
- return(0);
- }
- /*
- * serve: set up a shell for the remote process, and pass data.
- */
- #define RD 0
- #define WT 1
- serve(r)
- register struct request *r;
- {
- int pid = getpid(), writer, n, uid, ok;
- int oldnet;
- char user[32];
- struct passwd *pw;
- char home[32], path[128], shell[16], mail[64], term[32], logname[64];
- /*
- * Get the user info from the request header, and set our parameters
- */
- n = sscanf(r->r_data, "%d %s %s", &uid, user, term);
- memcpy(client, r->r_port.srcaddr, ETHERSIZE);
- pw = getpwnam(user);
- if(pw == NULL) {
- n = sprintf(r->r_data, "User '%s' not known here", user);
- send(r, n, TERMINATE, client);
- exit(0);
- }
- if(pw->pw_uid != uid) {
- n = sprintf(r->r_data, "User '%s' and uid '%d' don't match",
- user, uid);
- send(r, n, TERMINATE, client);
- exit(0);
- }
- #ifdef SECURE
- if(uid == 0) {
- n = sprintf(r->r_data, "Secure server: root access not allowed");
- send(r, n, TERMINATE, client);
- exit(0);
- }
- #endif
- setpgrp(); /* Set up a process group */
- setgid(pw->pw_gid);
- setuid(pw->pw_uid);
- sprintf(mail, "MAIL=/usr/mail/%s", user);
- sprintf(path, "PATH=:/usr/ucb:/bin:/usr/bin");
- sprintf(logname, "LOGNAME=%s", user);
- sprintf(shell, "SHELL=%s", pw->pw_shell);
- sprintf(home, "HOME=%s", pw->pw_dir);
- putenv(home); putenv(path); putenv(shell);
- putenv(mail); putenv(logname);
- putenv(term);
- chdir(pw->pw_dir);
- if(debug) {
- fprintf(stderr, "Server request from %s\n", getenv("LOGNAME"));
- }
- server[PIDMSB] = (pid >> 8) & 0xff;
- server[PIDLSB] = pid & 0xff;
- oldnet = ethernet; /* save old port for a bit */
- if(configure(server, 3, getpid()) == -1) { /* We are this address */
- ethernet = oldnet; /* Use old port */
- sprintf(r->r_data, "Can't allocate port");
- send(r, strlen(r->r_data), TERMINATE, client);
- exit(1);
- }
- close(oldnet); /* OK - use the new port */
- /*
- * Inform the client of our new address
- */
- memcpy(r->r_data, mynode, ETHERSIZE);
- send(r, ETHERSIZE, ACCEPT, client);
- /*
- * Get the command which the client wishes us to execute
- */
- recv(r);
- memcpy(cmd, r->r_data, r->r_size);
- /*
- * Special cases:
- * "login" - user wants a real login - use the PC-Interface pttys
- * "fileserver" - user wants to transfer files.
- */
- if(!strcmp(cmd, "login")) return(dologin(r));
- if(!strcmp(cmd, "fileserver")) return(fileserver(r));
- /*
- * Now start off the child process, and collect it's output
- */
- pipe(input);
- pipe(output);
- if(sh = fork()) {
- close(input[WT]);
- close(output[RD]);
- writer = getpid();
- if(reader = fork()) {
- ok = 1;
- signal(SIGPIPE, endproc);
- while(ok) {
- recv(r);
- if(debug) {
- fprintf(stderr, "server: got [%s] from %s\n",
- r->r_data, ipaddr(r->r_port.srcaddr));
- }
- ok = passon(r, output[WT]);
- }
- sigterm();
- }
- else {
- signal(SIGTERM, SIG_DFL);
- while((n = read(input[RD], r->r_data, sizeof r->r_data)) != -1) {
- send(r, n, DATA, client);
- if(debug) {
- fprintf(stderr, "server: %s sent to %s\n",
- r->r_data, ipaddr(client));
- }
- }
- sprintf(r->r_data, "hangup\n");
- send(r, strlen(r->r_data), TERMINATE, client);
- skill(writer, SIGKILL);
- exit(0);
- }
- }
- else doexec(r); /* exec the child shell */
- }
- /*
- * doexec: perform exec of requested procedure
- */
- doexec(r)
- struct request *r;
- {
- char *argv[6];
- split(cmd, argv);
- close(0); close(1); close(2);
- /*
- * Duplicate READ side of output as stdin
- */
- if(dup(output[RD]) != 0) perror("dup(input) != 0");
- /*
- * Duplicate WRITE side of input as stdout & stderr
- */
- if(dup(input[WT]) != 1) perror("dup(output) != 1");
- if(dup(input[WT]) != 2) perror("dup(output) != 2");
- /*
- * close all the parent's pipes - they're duplicated
- */
- close(input[0]); close(input[1]);
- close(output[0]); close(output[1]);
- close(ethernet);
- signal(SIGINT, SIG_DFL);
- signal(SIGQUIT, SIG_DFL);
- execvp(program, argv);
- sprintf(r->r_data, "Cannot exec %s\n", cmd);
- send(r, strlen(r->r_data), DATA, client);
- exit(1);
- }
- split(p, argv)
- register char *p;
- char **argv;
- {
- int n = 1;
- char *f;
- static char name[16];
- argv[0] = p;
- while(*p) {
- if(*p == ' ') {
- *p++ = '\0';
- while(*p == ' ') p++;
- argv[n++] = p;
- }
- else p++;
- }
- strcpy(program, argv[0]);
- if(f = strrchr(argv[0], '/')) f++;
- else f = argv[0];
- sprintf(name, "-%s", f);
- argv[0] = name;
- argv[n++] = NULL;
- }
-
- SHAR_EOF
- if test 6188 -ne "`wc -c < 'server.c'`"
- then
- echo shar: "error transmitting 'server.c'" '(should have been 6188 characters)'
- fi
- fi
- echo shar: "extracting 'connect.c'" '(6204 characters)'
- if test -f 'connect.c'
- then
- echo shar: "will not over-write existing file 'connect.c'"
- else
- cat << \SHAR_EOF > 'connect.c'
- /*
- * Copyright (C) 1988 Dave Settle. All rights reserved.
- * Permission is granted to use, copy and modify this software, providing
- * that it is not sold for profit, and that this copyright notice is retained
- * in any copies of the source.
- */
- /*
- * connect.c: connect tty to remote host.
- */
-
- #include <sys/types.h>
- #include <sys/signal.h>
- #include <sys/errno.h>
- #include <sys/utsname.h>
- #include <termio.h>
- #include <pwd.h>
-
- struct passwd *getpwuid(), *getpwnam();
- char *getlogin();
- int (*signal())();
-
- extern int errno;
- #include <stdio.h>
-
- #define MAIN
- #include "ni.h"
-
- char remoteshell[] = {0,0,0,0,0,0};
-
- struct request request;
-
- int reader, writer; /* Processes */
-
- int login = 0; /* Are we doing a login? */
-
- #define COOKED 0
- #define RAW 1
- struct termio raw, cooked; /* To allow screen mode changes */
- int screenmode = COOKED, toggle(), trap();
-
- wakeup(){
- signal(SIGALRM, wakeup);
- }
- /*
- * Got a signal - die. Writer is child process here.
- */
- die(sig){
- if(sig) printf("Connection closed.\r\n");
- if((getpid() == writer) && reader) kill(reader, SIGTERM);
- else if(writer) terminate(writer);
- send(&request, 0, TERMINATE, server);
- if(cooked.c_oflag) ioctl(fileno(stdout), TCSETA, &cooked);
- exit(0);
- }
-
- sendsig(sig)
- {
- struct request request;
- signal(sig, sendsig);
- if(sig == SIGINT) send(&request, 0, RMTSIGINT, server);
- if(sig == SIGQUIT) send(&request, 0, RMTSIGQUIT, server);
- }
-
-
- main(argc, argv)
- char **argv;
-
- {
- struct utsname uts;
- register char *sys = argv[argc - 1];
- int i;
- if(argc < 2) {
- printf("usage: %s hostname\n", argv[0]);
- exit(1);
- }
- uname(&uts);
- for(i=1;i<argc;i++) if(*argv[i] == '-') switch(argv[i][1]) {
- case 'l':
- login = 1;
- break;
- case 'd':
- debug = 1;
- break;
- }
- signal(SIGALRM, wakeup);
- signal(SIGTERM, SIG_IGN);
- if(configure(client, 3, getpid()) == -1) exit(1);
- if((i = hostaddr(argv[argc - 1])) == -1) {
- printf("Host '%s' not known\n", argv[argc - 1]);
- exit(1);
- }
- else server[NODE] = i;
- connect(server, sys);
- return(0);
- }
- /*
- * connect(addr): set up connection to ethernet address 'addr' (system 'sys')
- */
- connect(addr, sys)
- char *addr, *sys;
- {
- register struct request *r = &request;
- char *shell, *user;
- int n;
- struct passwd *pw;
- /*
- * send off our login name and uid to remote host.
- * also send timezone.
- */
- if((user = getlogin()) == NULL)
- pw = getpwuid(getuid());
- else
- pw = getpwnam(user);
- if(pw == NULL) {
- printf("Can't determine your user name!\n");
- exit(1);
- }
- if(*pw->pw_name == 0) {
- printf("Your user name is NULL! You seem to be %s\n",
- user ? user : "unknown");
- exit(1);
- }
- printf("Trying to connect to %s ... ", ipaddr(addr));
- fflush(stdout);
- sprintf(r->r_data, "%d %s TERM=%s",
- pw->pw_uid, pw->pw_name, getenv("TERM"));
- n = strlen(r->r_data);
- send(r, n, REQUEST, addr);
- recv(r);
- if(r->r_type == TERMINATE) {
- printf("rejected!\n%s: %s\n", sys, r->r_data);
- exit(0);
- }
- memcpy(server, r->r_port.srcaddr, ETHERSIZE);
- /*
- * trap signals from here on, so that we can terminate the remote side.
- */
- signal(SIGQUIT, toggle);
- signal(SIGINT, sendsig);
- signal(SIGHUP, die);
- printf("OK\nStarting remote %s ... ", login ? "login" : "shell");
- fflush(stdout);
- if(login) n = sprintf(r->r_data, "login");
- else {
- shell = getenv("SHELL");
- if(shell == 0) shell = "/bin/sh";
- n = sprintf(r->r_data, "%s -i", shell);
- }
- send(r, n, REQUEST, server);
- recv(r);
- if(r->r_type == TERMINATE) {
- printf("rejected!\n%s: %s\n", sys, r->r_data);
- exit(0);
- }
- printf("OK\nConnection complete ... server is %s\n", ipaddr(server));
- /*
- * Set up the termio structures needed for mode swapping
- */
- ioctl(fileno(stdin), TCGETA, &cooked);
- ioctl(fileno(stdin), TCGETA, &raw);
- raw.c_oflag &= ~OPOST;
- raw.c_cc[VMIN] = 1;
- raw.c_cc[VTIME] = 0;
- raw.c_iflag = 0;
- raw.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
- screenmode = COOKED;
- /*
- * fork for reader and writer processes.
- */
- reader = getpid();
- if(writer = fork()) {
- /*
- * If we are starting a remote login via a ptty, then the remote host will
- * echo, so set to raw mode. SIGQUIT will close the connection.
- */
- if(login) {
- screenmode = RAW;
- ioctl(fileno(stdin), TCSETA, &raw);
- signal(SIGQUIT, die);
- signal(SIGINT, trap);
- }
- else {
- /*
- * Send the remote shell an initial newline, so that the user sees a prompt.
- */
- r->r_data[0] = '\n';
- send(r, 1, DATA, server);
- }
- while(n = read(fileno(stdin), r->r_data, sizeof r->r_data)) {
- if(n == -1) {
- if(errno == EINTR) continue;
- else break;
- }
- if(debug) {
- printf("client: sent [");
- write(fileno(stdout), r->r_data, n);
- printf("] to %s\n", ipaddr(server));
- }
- send(r, n, DATA, server);
- }
- send(r, 0, TERMINATE, server);
- terminate(writer);
- ioctl(fileno(stdout), TCSETA, &cooked);
- exit(0);
- }
- else {
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- while(1) {
- recv(r);
- if(debug) {
- printf("client: got [");
- write(fileno(stdout), r->r_data, r->r_size);
- printf("] from %s\n", ipaddr(r->r_port.srcaddr));
- }
- if(r->r_type == TERMINATE) {
- printf("Lost remote connection [");
- fflush(stdout);
- write(fileno(stdout), r->r_data, r->r_size);
- printf("]\n");
- kill(reader, SIGTERM);
- ioctl(fileno(stdout), TCSETA, &cooked);
- exit(0);
- }
- write(fileno(stdout), r->r_data, r->r_size);
- }
- }
- }
- /*
- * toggle: change screen mode from RAW <-> COOKED
- */
- toggle(sig){
- static int (*handler)();
- signal(sig, toggle);
- switch(screenmode) {
- case COOKED:
- handler = signal(SIGINT, trap);
- ioctl(fileno(stdin), TCSETA, &raw);
- putchar(07); /* beep */
- fflush(stdout);
- screenmode = RAW;
- break;
- case RAW:
- if(handler) signal(SIGINT, handler);
- ioctl(fileno(stdin), TCSETA, &cooked);
- printf("[cooked]");
- fflush(stdout);
- screenmode = COOKED;
- break;
- }
- }
- /*
- * trap interrupts in raw mode, substitute 'del' char
- * We can't just ignore interrupts, otherwise we can't switch out of raw mode.
- */
- trap(sig){
- struct request r;
- signal(sig, trap);
- switch(sig) {
- default:
- case SIGINT:
- r.r_data[0] = cooked.c_cc[VINTR];
- break;
- case SIGQUIT:
- r.r_data[0] = cooked.c_cc[VQUIT];
- break;
- }
- send(&r, 1, DATA, server);
- }
-
- SHAR_EOF
- if test 6204 -ne "`wc -c < 'connect.c'`"
- then
- echo shar: "error transmitting 'connect.c'" '(should have been 6204 characters)'
- fi
- fi
- echo shar: "extracting 'rcp.c'" '(5486 characters)'
- if test -f 'rcp.c'
- then
- echo shar: "will not over-write existing file 'rcp.c'"
- else
- cat << \SHAR_EOF > 'rcp.c'
- /*
- * rcp.c: NOT the Berkeley version.
- *
- * rcp [system!]source ... [system!]dest
- * e.g. rcp a!file1 b!file2 c!/usr/tmp
- *
- * AUTHOR: Dave Settle, THORN EMI SMB Business Software, June 86
- *
- * Electronic address:
- * dave%smb@ukc
- * dave@smb.co.uk
- *
- */
- #include <stdio.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/utsname.h>
- #include <pwd.h>
-
- #define MAIN
- #include "ni.h"
- #include "ftp.h"
-
- extern int debug;
-
- char *getenv(), *getlogin();
- char *sysname(), *filename(), *lastpart();
- struct passwd *getpwuid(), *getpwnam();
- struct request request;
- time_t time(), interval();
- long kbytes();
-
- die(sig){
- struct request req;
- if(sig) printf("\r\n%s: server terminated\n",
- (sig == SIGINT) ? "Interrupt" : "Quit");
- send(&req, 0, TERMINATE, server);
- exit(1);
- }
-
- extern char *panicstr;
- panic(sig){
- printf("server has terminated me: %s\n",
- panicstr ? panicstr : "no reason");
- exit(0);
- }
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- /*
- * check if the destination is local or remote.
- */
- int i, n, start = 1;
- struct utsname uts;
- char *user;
- struct passwd *pw;
- register struct request *r = &request;
- user = getenv("LOGNAME");
- if(user == NULL) printf("who are you?\n");
- /*
- * find out node name
- */
- uname(&uts);
- strncpy(localnode, uts.nodename, sizeof uts.nodename);
- #ifdef DEBUG
- printf("localnode: %s\n", localnode);
- #endif
- hostname = NULL;
- for(i=1;i<argc;i++) {
- if(*argv[i] == '-') {
- switch(argv[i][1]) {
- case 'd':
- debug = 1;
- start = i + 1;
- break;
- }
- continue;
- }
- if(remote(argv[i])) {
- if(hostname && strcmp(hostname, sysname(argv[i]))) {
- printf("Cannot talk to %s AND %s!\n",
- hostname, sysname(argv[i]));
- exit(1);
- }
- else hostname = sysname(argv[i]);
- }
- }
- /*
- * If this isn't really a remote copy, subsitute 'cp'
- */
- if(hostname == 0) {
- argv[0] = "cp";
- argv[argc] = 0;
- execv("/bin/cp", argv);
- exit(1);
- }
- if((i = hostaddr(hostname)) == -1) {
- printf("Host '%s' not known\n", hostname);
- exit(1);
- }
- else server[NODE] = i;
- if(configure(client, WINDOW, getpid()) == -1) {
- perror("/dev/ni");
- exit(1);
- }
- /*
- * send off our login name and uid to remote host.
- * also send term type.
- */
- if((user = getlogin()) == NULL)
- pw = getpwuid(getuid());
- else
- pw = getpwnam(user);
- if(pw == NULL) {
- printf("Can't determine your user name!\n");
- exit(1);
- }
- if(*pw->pw_name == 0) {
- printf("Your user name is NULL! You seem to be %s\n",
- user ? user : "unknown");
- exit(1);
- }
- printf("Trying to connect to %s ... ", ipaddr(server));
- fflush(stdout);
- sprintf(r->r_data, "%d %s TERM=%s",
- pw->pw_uid, pw->pw_name, getenv("TERM"));
- n = strlen(r->r_data);
- send(r, n, REQUEST, server);
- recv(r);
- if(r->r_type != ACCEPT) {
- printf("rejected!\n%s: %s\n", hostname, r->r_data);
- exit(0);
- }
- memcpy(server, r->r_port.srcaddr, ETHERSIZE);
- printf("OK\nStarting remote file server ... "); fflush(stdout);
- /*
- * trap signals from here on, so that we can terminate the remote side.
- */
- signal(SIGQUIT, die);
- signal(SIGINT, die);
- signal(SIGHUP, die);
- signal(SIGTERM, panic);
- n = sprintf(r->r_data, "fileserver");
- send(r, n, REQUEST, server);
- recv(r);
- if(r->r_type != ACCEPT) {
- printf("rejected!\n%s: %s\n", hostname, r->r_data);
- exit(1);
- }
- printf("OK\n");
- /*
- * Now send (or receive) the files.
- */
- if(remote(argv[argc - 1]))
- for(i=start;i<(argc - 1);i++)
- sendit(filename(argv[i]), filename(argv[argc - 1]));
- else
- for(i=start;i<(argc - 1);i++)
- getit(filename(argv[i]), filename(argv[argc - 1]));
- die(0);
- /*NOTREACHED*/
- }
- /*
- * sendit: send local filename to remote server.
- */
- sendit(local, remote)
- char *local, *remote;
- {
- register int n, f;
- register struct request *r = &request;
- time_t start;
- struct stat statb;
- long kb;
- if((f = open(local, 0)) == -1) {
- perror(local);
- return(-1);
- }
- n = sprintf(r->r_data, "%d %s %s", fmode(local), local, remote);
- printf("%s: ", local); fflush(stdout);
- send(r, n, PUTFILE, server);
- recv(r);
- stat(local, &statb);
- start = time((long *) 0);
- kb = kbytes(statb.st_size);
- if(r->r_type == ACCEPT) {
- printf("[sending] "); fflush(stdout);
- if(ftpout(f, server))
- printf("OK (%d kb/sec)\n", kb / interval(start));
- }
- else printf("[%s] %s\n", hostname, r->r_data);
- close(f);
- return(0);
- }
- /*
- * getit: persuade remote host to send a file.
- */
- getit(remote, local)
- char *local, *remote;
- {
- register struct request *r = &request;
- register int n, f;
- int mode;
- char fname[128];
- time_t start;
- struct stat statb;
- long kb;
- int newfile;
- strcpy(fname, local);
- if(stat(local, &statb) != -1) {
- if((statb.st_mode & S_IFMT) == S_IFDIR)
- sprintf(fname, "%s/%s", local, lastpart(remote));
- newfile = 0;
- }
- else newfile = 1;
- if((f = creat(fname, 0666)) == -1) {
- perror(fname);
- return(-1);
- }
- n = sprintf(r->r_data, "%s", remote);
- printf("%s: ", fname); fflush(stdout);
- send(r, n, SENDFILE, server);
- recv(r);
- if(r->r_type == ACCEPT) {
- sscanf(r->r_data, "%d", &mode);
- if(newfile) chmod(fname, mode);
- start = time((long *) 0);
- printf("[receiving] "); fflush(stdout);
- if(ftpin(f, server, &kb))
- printf("OK (%d kb/sec)\n", kbytes(kb) / interval(start));
- else unlink(fname);
- close(f);
- return(0);
- }
- else {
- printf("rejected [%s: %s]\n", hostname, r->r_data);
- close(f);
- return(-1);
- }
- }
- long kbytes(size)
- long size;
- {
- size >>= 10;
- return(size ? size : 1);
- }
- long interval(start)
- {
- long i = time((long *) 0) - start;
- return(i ? i : 1);
- }
- SHAR_EOF
- if test 5486 -ne "`wc -c < 'rcp.c'`"
- then
- echo shar: "error transmitting 'rcp.c'" '(should have been 5486 characters)'
- fi
- fi
- echo shar: "extracting 'eth.c'" '(3689 characters)'
- if test -f 'eth.c'
- then
- echo shar: "will not over-write existing file 'eth.c'"
- else
- cat << \SHAR_EOF > 'eth.c'
- /*
- * Copyright (C) 1988 Dave Settle. All rights reserved.
- * Permission is granted to use, copy and modify this software, providing
- * that it is not sold for profit, and that this copyright notice is retained
- * in any copies of the source.
- */
- /*
- * eth.c: various useful routines to talk to the ethernet.
- */
- #include <sys/types.h>
- #include <sys/errno.h>
- #include <stdio.h>
-
- #include "ni.h"
-
- #define MINBUF 64 + 64 /* min 128 bytes data */
-
- char *panicstr; /* cause (if any) of a SIGTERM */
-
- /*
- * configure the 'ethernet' fd so that we appear as node 'thisnode'
- * Allocate 'nbufs' to cope with expected data.
- */
- configure(thisnode, nbufs, pid)
- char *thisnode;
- {
- if((ethernet = open("/dev/ni", 2)) == -1) {
- perror("/dev/ni");
- return(-1);
- }
- if(ioctl(ethernet, NIGETA, &port)) {
- perror("NIGETA");
- return(-1);
- }
- thisnode[NODE] = port.srcaddr[LSB];
- thisnode[PIDMSB] = (pid & 0xff00) >> 8;
- thisnode[PIDLSB] = pid & 0xff;
- #ifdef DEBUG
- printf("Running on node %s\n", ipaddr(port.srcaddr));
- #endif
- port.type = ETHERTYPE;
- if(nbufs) port.rcvq_sz = nbufs;
- port.rcvb_sz = (sizeof (struct request) + 3) & ~3;
- memcpy(port.srcaddr, thisnode, ETHERSIZE);
- port.protocol = PROTOCOL;
- if(ioctl(ethernet, NISETA, &port)) {
- perror("NISETA");
- return(-1);
- }
- #ifdef DEBUG
- printf("Port configured as node %s\n", ipaddr(thisnode));
- #endif
- memcpy(mynode, thisnode, ETHERSIZE);
- return(0);
- }
- /*
- * recv: receive a request from the ethernet
- * If it's a request to terminate, propagate a SIGTERM signal.
- * This means that users of this routine can decide on what action to take,
- * and also be sure that no TERMINATE packets will not be detected.
- */
- recv(r)
- register struct request *r;
- {
- if(read(ethernet, r, sizeof (struct request)) == -1) {
- r->r_type = UNDEFINED;
- r->r_size = 0;
- return(-1);
- }
- if(r->r_type == TERMINATE) {
- panicstr = r->r_data;
- skill(getpid(), SIGTERM);
- }
-
- return(0);
- }
- /*
- * send request to specified node
- */
- send(r, size, type, node)
- struct request *r;
- char *node;
- {
- int total, min = sizeof (EI_PORT) + 52;
- memcpy(r->r_port.srcaddr, mynode, ETHERSIZE);
- memcpy(r->r_port.destaddr, node, ETHERSIZE);
- memcpy(r->r_port.ptype, myprotocol, 2);
- r->r_type = type;
- r->r_size = size;
- total = sizeof (struct request) - ((sizeof r->r_data) - size);
- total = total > min ? total : min;
- if(write(ethernet, r, total) == -1) {
- perror("write error");
- printf("Packet: src %s ", ipaddr(r->r_port.srcaddr));
- printf("dest %s\n", ipaddr(r->r_port.destaddr));
- return(-1);
- }
- return(0);
- }
- /*
- * perror
- */
- extern char *sys_errlist[];
- extern int errno;
- extern int sys_nerr;
-
- char *ni_error[] = {
- "Bad network address",
- "Bad port configuration specification",
- "Port not configured",
- "Open failure - out of memory?",
- "HLP circuit failure",
- "HLP fault",
- "Port not available",
- "Network not available",
- "Driver fault",
- "Hardware failure",
- "Network fault",
- "Bad packet",
- "Device has been reset"
- };
-
- perror(msg)
- char *msg;
- {
- char *e;
- if((errno > 200) && (errno < 213)) e = ni_error[errno - 200];
- else e = sys_errlist[errno];
- fprintf(stderr, "%s: %s [%d]\n", msg, e, errno);
- }
- /*
- * used only with 'sdb'
- */
- dump(s)
- char *s;
- {
- printf("%s\n", ipaddr(s));
- }
- hostaddr(host)
- char *host;
- {
- FILE *map;
- char name[32];
- int id;
- if((map = fopen(MAP, "r")) == NULL) return(0);
- while(fscanf(map, "%s%x", name, &id) != EOF)
- if(!strcmp(name, host)) {
- fclose(map);
- return(id);
- }
- fclose(map);
- return(-1);
- }
- /*
- * skill: 'safe' kill. There's a bug somewhere when we kill proc 0 and log
- * everyone out. This is a wrokaround.
- */
- skill(proc, sig){
- if(proc < 1) {
- errno = EINVAL;
- return(-1);
- }
- return(kill(proc, sig));
- }
-
- SHAR_EOF
- if test 3689 -ne "`wc -c < 'eth.c'`"
- then
- echo shar: "error transmitting 'eth.c'" '(should have been 3689 characters)'
- fi
- fi
- echo shar: "extracting 'ipaddr.c'" '(466 characters)'
- if test -f 'ipaddr.c'
- then
- echo shar: "will not over-write existing file 'ipaddr.c'"
- else
- cat << \SHAR_EOF > 'ipaddr.c'
- /*
- * Copyright (C) 1988 Dave Settle. All rights reserved.
- * Permission is granted to use, copy and modify this software, providing
- * that it is not sold for profit, and that this copyright notice is retained
- * in any copies of the source.
- */
- /*
- * ipaddr: print address as xx.xx.xx.xx.xx.xx
- */
- char *ipaddr(a)
- char *a;
- {
- register int i;
- static char s[26];
- for(i=0;i<5;i++) sprintf(s + (i * 3), "%02x.", a[i]);
- sprintf(s + 15, "%02x", a[5]);
- return(s);
- }
-
- SHAR_EOF
- if test 466 -ne "`wc -c < 'ipaddr.c'`"
- then
- echo shar: "error transmitting 'ipaddr.c'" '(should have been 466 characters)'
- fi
- fi
- echo shar: "extracting 'talk.c'" '(1303 characters)'
- if test -f 'talk.c'
- then
- echo shar: "will not over-write existing file 'talk.c'"
- else
- cat << \SHAR_EOF > 'talk.c'
- /*
- * talk.c: routines to talk to the remote shell, run on the remote system
- */
- #include "ni.h"
-
-
- passon(r, output)
- register struct request *r; /* stuff to send */
- int output; /* file descriptor to write on */
- {
- int ok = 1;
- switch(r->r_type) {
- case TERMINATE:
- ok = 0;
- break;
- case RMTSIGINT:
- kill(0, SIGINT);
- break;
- case RMTSIGQUIT:
- kill(0, SIGQUIT);
- break;
- case DATA:
- write(output, r->r_data, r->r_size);
- break;
- default:
- sprintf(r->r_data, "Bad packet type %d\n", r->r_type);
- send(r, strlen(r->r_data), DATA, client);
- }
- return(ok);
- }
- #define PTTY "/dev/ptc"
- #define MAXPTTYS 8
- /*
- * special case routine - use the PC-Interface pseudo-ttys to get a real
- * remote login!
- */
- dologin(r)
- register struct request *r;
- {
- int dev; /* file descriptor */
- int i, n, reader;
- char name[sizeof PTTY + 4];
- for(i=0;i<MAXPTTYS;i++) {
- sprintf(name, "%s%02d", PTTY, i);
- if((dev = open(name, 2)) != -1) break;
- }
- if(dev == -1) {
- n = sprintf(r->r_data, "No PC-Interface ports available");
- send(r, n, TERMINATE, client);
- exit(1);
- }
- if(reader = fork()) {
- while(1) {
- recv(r);
- if(passon(r, dev) == 0) {
- skill(reader, SIGTERM);
- exit(0);
- }
- }
- }
- else {
- while(1) {
- n = read(dev, r->r_data, sizeof r->r_data);
- send(r, n, DATA, client);
- }
- }
- }
-
-
- SHAR_EOF
- if test 1303 -ne "`wc -c < 'talk.c'`"
- then
- echo shar: "error transmitting 'talk.c'" '(should have been 1303 characters)'
- fi
- fi
- echo shar: "extracting 'sub.c'" '(1703 characters)'
- if test -f 'sub.c'
- then
- echo shar: "will not over-write existing file 'sub.c'"
- else
- cat << \SHAR_EOF > 'sub.c'
- /*
- * sub.c: general subroutines for "rcp"
- * remote(s): check if "s" refers to a local(0) or remote(1) file.
- * sysname(s): return systemname assosciated with s. "localnode" returned
- * if there is no specific "sys!" prefix.
- * filename(s): return filname part - strip first system prefix, if there is one
- *
- * fmode(s): return value of file mode.
- *
- * lastpart(f): return last entry of path 'f'
- */
-
- #define rindex strrchr
- #define index strchr
-
- char *filename(), *sysname(), *lastpart(), *malloc(),
- *strrchr(), *strchr();
- extern char *sys_errlist[];
- #include "errno.h"
- #include <stdio.h>
- #include <time.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- #include "ni.h"
- long time();
- char *asctime();
- struct tm *localtime();
-
- remote(s)
- char *s;
- {
- if(filename(s) == s) return(0);
- else return(1);
- }
- /*
- * sysname(f): get system name part of file name.
- * if no system present, return localnode
- */
- char *sysname(f)
- char *f;
- {
- register char *p, *sys;
- register int length;
- if((p = filename(f)) == f) return(localnode);
- else {
- sys = malloc(length = p - f);
- strncpy(sys, f, length - 1);
- sys[length - 1] = 0;
- return(sys);
- }
- }
- /*
- * filename(f): return file name part of f
- * Strips the first (and only the first) system, if there is one.
- * [8] Also allow ':' as system flag.
- */
- char *filename(f)
- register char *f;
- {
- register char *s;
- if((s = index(f, '!')) || (s = index(f, ':'))) return(++s);
- else return(f);
- }
- bang(c)
- char c;
- {
- if((c == '!') || (c == ':')) return(1);
- else return(0);
- }
-
- fmode(f)
- char *f;
- {
- struct stat s;
- if(stat(f, &s) == -1) return(0664);
- return(s.st_mode);
- }
-
- char *lastpart(f)
- char *f;
- {
- char *l;
- if(l = rindex(f, '/')) return(++l);
- else return(f);
- }
-
- SHAR_EOF
- if test 1703 -ne "`wc -c < 'sub.c'`"
- then
- echo shar: "error transmitting 'sub.c'" '(should have been 1703 characters)'
- fi
- fi
- echo shar: "extracting 'file.c'" '(2159 characters)'
- if test -f 'file.c'
- then
- echo shar: "will not over-write existing file 'file.c'"
- else
- cat << \SHAR_EOF > 'file.c'
- /*
- * file.c: server end of the "rcp" function.
- * Send or get files. Relies on the transport interface to detect errors,
- * only checks sequence numbers to identify lost packets.
- * If a packet is lost, then the transfer is abandoned and restarted - this
- * is not expected to happen often.
- */
- #include <sys/types.h>
- #include <sys/stat.h>
-
- #include "ni.h"
-
- #include "ftp.h"
-
- extern char *sys_errlist[];
- extern int errno;
-
- char *lastpart();
-
- fileserver(r)
- register struct request *r;
- {
- register int f, n;
- int mode, newfile;
- long kb;
- struct stat statb;
- char fname[128], local[128], remote[128];
- /*
- * re-configure the ethernet port to handle sufficient buffers
- */
- close(ethernet);
- configure(server, WINDOW, getpid());
- send(r, 0, ACCEPT, client);
- signal(SIGTERM, SIG_DFL); /* TERMINATE packet kills */
- while(1) {
- recv(r); /* get request */
- switch(r->r_type) {
- case TERMINATE:
- exit(1);
- break;
- case SENDFILE:
- strncpy(fname, r->r_data, r->r_size);
- fname[r->r_size] = 0;
- if((f = open(fname, 0)) == -1) {
- n = sprintf(r->r_data, "%s: %s", fname,
- sys_errlist[errno]);
- send(r, n, REJECT, client);
- }
- else {
- stat(fname, &statb);
- n = sprintf(r->r_data, "%d", statb.st_mode & 0777);
- send(r, n, ACCEPT, client);
- ftpout(f, client);
- close(f);
- }
- break;
- case PUTFILE:
- n = sscanf(r->r_data, "%d %s %s",
- &mode, remote, local);
- if(n != 3) {
- n = sprintf(r->r_data, "Illegal request parameters");
- send(r, n, REJECT, client);
- break;
- }
- strcpy(fname, local);
- if(stat(local, &statb) != -1) {
- if((statb.st_mode & S_IFMT) == S_IFDIR)
- sprintf(fname, "%s/%s", local,
- lastpart(remote));
- newfile = 0;
- }
- else newfile = 1;
- if((f = creat(fname, 0666)) == -1) {
- n = sprintf(r->r_data, "%s: %s", fname,
- sys_errlist[errno]);
- send(r, n, REJECT, client);
- }
- else {
- if(newfile) chmod(fname, mode);
- send(r, 0, ACCEPT, client);
- if(!ftpin(f, client, &kb)) unlink(fname);
- close(f);
- }
- break;
- default:
- n = sprintf(r->r_data, "Illegal request function %d",
- r->r_type);
- send(r, n, REJECT, client);
- }
- }
- }
- SHAR_EOF
- if test 2159 -ne "`wc -c < 'file.c'`"
- then
- echo shar: "error transmitting 'file.c'" '(should have been 2159 characters)'
- fi
- fi
- echo shar: "extracting 'terminate.c'" '(512 characters)'
- if test -f 'terminate.c'
- then
- echo shar: "will not over-write existing file 'terminate.c'"
- else
- cat << \SHAR_EOF > 'terminate.c'
- #include <sys/signal.h>
-
- #define GRACETIME 1
- /*
- * terminate: log out the child shell. Sends SIGHUP, SIGTERM, SIGKILL
- * until the child exits.
- */
- terminate(child)
- {
- int status;
- if(child < 1) return(0);
- kill(child, SIGHUP);
- alarm(GRACETIME);
- if(wait(&status) == -1) {
- kill(child, SIGTERM);
- alarm(GRACETIME);
- if(wait(&status) == -1) {
- kill(child, SIGKILL);
- alarm(GRACETIME);
- if(wait(&status) == -1) {
- printf("Cannot kill child pid %d\n", child);
- status = 0;
- }
- }
- }
- alarm(0);
- }
-
- SHAR_EOF
- if test 512 -ne "`wc -c < 'terminate.c'`"
- then
- echo shar: "error transmitting 'terminate.c'" '(should have been 512 characters)'
- fi
- fi
- echo shar: "extracting 'mynode.c'" '(627 characters)'
- if test -f 'mynode.c'
- then
- echo shar: "will not over-write existing file 'mynode.c'"
- else
- cat << \SHAR_EOF > 'mynode.c'
- /*
- * Copyright (C) 1988 Dave Settle. All rights reserved.
- * Permission is granted to use, copy and modify this software, providing
- * that it is not sold for profit, and that this copyright notice is retained
- * in any copies of the source.
- */
- /*
- * mynode.c: print physical ethernet address of the local node.
- */
-
- #include <sys/ni.h>
-
- main(){
- NI_PORT port;
- int ethernet;
- if((ethernet = open("/dev/ni", 2)) == -1) {
- perror("/dev/ni");
- exit(1);
- }
- if(ioctl(ethernet, NIGETA, &port)) {
- perror("NIGETA");
- exit(1);
- }
- printf("Physical ethernet address: %s\n", ipaddr(port.srcaddr));
- close(ethernet);
- exit(0);
- }
- SHAR_EOF
- if test 627 -ne "`wc -c < 'mynode.c'`"
- then
- echo shar: "error transmitting 'mynode.c'" '(should have been 627 characters)'
- fi
- fi
- echo shar: "extracting 'ftp.c'" '(7077 characters)'
- if test -f 'ftp.c'
- then
- echo shar: "will not over-write existing file 'ftp.c'"
- else
- cat << \SHAR_EOF > 'ftp.c'
- /*
- * ftp.c: the 'file transfer' protocols.
- * Sliding-window protocol with selective retransmit.
- */
- #include "ni.h"
-
- #include "ftp.h"
-
- extern char *sys_errlist[];
- int debug;
-
- #define NULL 0
- #define slotno(num) ((num) % WINDOW)
-
- struct request buffer[WINDOW];
- struct request *packet[WINDOW];
- int retry = 0;
- sequence_t lower, upper, num;
-
- wakeup(){
- signal(SIGALRM, wakeup);
- }
- /*
- * ftpout: send the file to the indicated host.
- */
- ftpout(f, addr)
- char *addr;
- {
- struct request ackreq, *ack = &ackreq;
- register struct request *r;
- register int n;
- int i, eof = 0;
- lower = upper = num = 0;
- retry = 0;
- for(i=0;i<WINDOW;i++) packet[i] = NULL;
- wakeup();
- while(1) {
- /*
- * If the window is not sent, send another packet.
- * If last packet was null, then all data has been sent.
- */
- while(!fullwindow(lower, upper) && !eof) {
- num = upper++;
- r = &buffer[slotno(num)];
- packet[slotno(num)] = r;
- r->r_sequence = num;
- n = read(f, r->r_data, sizeof r->r_data);
- /*
- * read error causes premature EOF
- */
- if(n == -1) n = 0;
- if(debug)
- printf("Sending packet %d\n", r->r_sequence);
- /*
- * Reset the counter for ack timeouts, then send out the block
- */
- retry = 0;
- send(r, n, DATA, addr);
- if(n == 0) eof = 1;
- }
- /*
- * We have to wait for an ACK from the other end ...
- * If it's an ACK, then the sequence field determines which packet is OK
- * If it's a NACK, then the data is a list of packets which
- * must have got lost somewhere. so we re-transmit them.
- */
- if(debug) printf("Window full - waiting for ack\n");
- alarm(TRANSIT);
- recv(ack);
- alarm(0);
- switch(ack->r_type) {
- /*
- * ACK - mark the packet as sent (delete pointer).
- * Move lower bound of window up as far as possible.
- */
- case ACCEPT:
- if(debug)
- printf("Got ack on packet %d\n", ack->r_sequence);
- release(ack->r_sequence);
- break;
- case REJECT:
- if(debug)
- printf("Got reject (ack packet %d)\n", ack->r_sequence);
- release(ack->r_sequence);
- for(i=0;i<ack->r_size;i++) {
- if(debug)
- printf("\tpacket %d\n", ack->r_data[i]);
- r = packet[slotno(ack->r_data[i])];
- if(inwindow(ack->r_data[i], lower, upper))
- send(r, r->r_size, DATA, addr);
- }
- break;
- /*
- * Timeout waiting for ACK - retransmit all the outstanding packets.
- */
- case UNDEFINED:
- printf("Timeout\n");
- if(retry++ > MAXRETRY) {
- printf("Too many timeouts - ftp abort\n");
- n = sprintf(ack->r_data, "Too many timeouts");
- send(ack, n, TERMINATE, addr);
- exit(0);
- }
- for(i=0;i<WINDOW;i++) if(packet[i])
- send(packet[i], packet[i]->r_size, DATA, addr);
- break;
- default:
- printf("Illegal ack type %d\n", ack->r_type);
- } /* end switch */
- /*
- * If we've transmitted all the data, and got acks back for all the packets
- * then the transfer is complete.
- */
- if(eof && debug)
- printf("EOF - waiting to clear %d - %d\n", lower, upper);
- if(eof && (upper == lower)) return(1);
- } /* end data loop */
- }
- /*
- * ftpin: recv data, plonk in file.
- * Packet with data size 0 ends file transmission.
- */
- ftpin(f, addr, kb)
- char *addr;
- long *kb; /* data size received */
- {
- register struct request *r;
- long count = 0;
- int i, eof = 0;
- struct request ackreq, *ack = &ackreq;
- register int n;
- sequence_t slot, datablock, last, diskblock = 0;
- lower = num = 0;
- upper = WINDOW - 1;
- datablock = 0;
- for(i=0;i<WINDOW;i++) packet[i] = NULL;
- while(1) {
- /*
- * Zero received buffer space, so we know what has got here
- */
- retry = 0;
- if(debug)
- printf("Waiting for %d - %d, using buffer %d\n",
- lower, lower + WINDOW, slotno(datablock));
- r = &buffer[slotno(datablock++)]; /* get a buffer */
- recv(r);
- switch(r->r_type) {
- /*
- * Normal data - fix in the correct place
- * If we missed packets in the sequence, ask for them again.
- */
- case DATA:
- upper = lower + WINDOW - 1;
- if(debug) printf("Received packet %d, size %d\n",
- r->r_sequence, r->r_size);
- /*
- * incoming packet not within our current window. The ack for a previous
- * packet must have got lost - send it again!
- * If the packet doesn't seem to fit anywhere, complain!
- */
- if(!inwindow(r->r_sequence, lower, upper)) {
- if(inwindow(r->r_sequence, lower - WINDOW, lower)) {
- ack->r_sequence = r->r_sequence;
- send(ack, 0, ACCEPT, addr);
- }
- else {
- if(debug) printf("packet %d out of bounds %d - %d\n",
- r->r_sequence, lower, upper);
- n = sprintf(ack->r_data, "protocol violation: packet %d arrived in window %d - %d\n",
- r->r_sequence, lower, upper);
- send(ack, n, TERMINATE, addr);
- exit(0);
- }
- datablock--;
- continue; /* out of window */
- }
- slot = slotno(r->r_sequence);
- if(packet[slot]) {
- if(debug) printf("Duplicate - ignored\n");
- datablock--;
- continue; /* duplicate */
- }
- packet[slot] = r;
- count += r->r_size;
- /*
- * Check for eof, and send ack for this packet.
- */
- if(r->r_size == 0) {
- eof = 1;
- last = r->r_sequence;
- }
- ack->r_sequence = r->r_sequence;
- send(ack, 0, ACCEPT, addr);
- /*
- * Write as many packets as possible.
- */
- while(r = packet[slotno(lower)]) {
- if(debug)
- printf("Packet %d written to disk\n", r->r_sequence);
- if(r->r_sequence != diskblock++) {
- printf("Bug detected! data block %d written as disk block %d\n",
- r->r_sequence, datablock - 1);
- n = sprintf(ack->r_data, "data block sequence error");
- send(ack, n, TERMINATE, addr);
- exit(1);
- }
- if(write(f, r->r_data, r->r_size) != r_size) {
- perror("write error");
- n = sprintf(ack->r_data, "write error: %s",
- sys_errlist[errno]);
- send(ack, n, TERMINATE, addr);
- exit(1);
- }
- packet[slotno(lower)] = NULL;
- lower++;
- }
- break;
- default:
- printf("Illegal ftp packet %d\n", r->r_type);
- } /* end switch */
- if(eof && (lower == (last + 1))) {
- *kb = count;
- return(1);
- }
- } /* end data loop */
- }
- /*
- * Check if 'num' falls between lbound and ubound
- */
- inwindow(number, lbound, ubound)
- sequence_t number, lbound, ubound;
- {
- while(1) {
- if(number == lbound) return(1);
- if(lbound == ubound) return(0);
- else lbound++;
- }
- }
- /*
- * retransmit: we were looking for packet 'last', but got packet 'this'
- * Ask for retransmit of intervening packets - this also acks packet 'this'
- */
- retransmit(last, this, ack, addr)
- sequence_t last, this;
- register struct request *ack;
- char *addr;
- {
- int j, n = 0;
- for(j=0;j<WINDOW;j++) if(packet[j] == NULL)
- ack->r_data[n++] = (sequence_t) lower + j;
- ack->r_sequence = this;
- send(ack, n, REJECT, addr);
- }
- /*
- * release: mark packet 'n' as being succesfully received.
- * Move lower bound of window up, if possible.
- */
- release(n)
- sequence_t n;
- {
- packet[slotno(n)] = NULL;
- while(packet[slotno(lower)] == NULL) {
- lower++;
- if(lower == upper) break;
- }
- if(debug) printf("Packet %d released - lbound now %d\n", n, lower);
- }
- /*
- * fullwindow: if distance between lower and upper is >= WINDOW
- */
- fullwindow(lower, upper)
- register sequence_t lower, upper;
- {
- register int n = 0;
- while(lower++ != upper) n++;
- if(n >= WINDOW) return(1);
- return(0);
- }
- SHAR_EOF
- if test 7077 -ne "`wc -c < 'ftp.c'`"
- then
- echo shar: "error transmitting 'ftp.c'" '(should have been 7077 characters)'
- fi
- fi
- echo shar: "extracting 'ni.h'" '(1591 characters)'
- if test -f 'ni.h'
- then
- echo shar: "will not over-write existing file 'ni.h'"
- else
- cat << \SHAR_EOF > 'ni.h'
- #include <sys/ni.h>
- #include <sys/signal.h>
-
- #ifdef MAIN
- #define EXTERN
- #else
- #define EXTERN extern
- #endif
-
- #define MAP "/usr/lib/ethernet.addr"
-
- EXTERN NI_PORT port;
- EXTERN int debug;
- EXTERN char *hostname, localnode[16];
-
- #define ETHERSIZE 6
-
- typedef char address_t[];
- typedef unsigned char sequence_t;
-
- #define PORT 4 /* plonk port id here */
- #define NODE 5 /* plonk lsb node address */
- #define LSB 5 /* lsb of node address */
- #define PIDMSB 3
- #define PIDLSB 4
-
- EXTERN int ethernet;
-
-
-
- #ifdef MAIN
- char server[] = {0x0f, 0x02, 0x02, 0, 0, NODE};
- #else
- extern char server[];
- #endif
-
-
- #ifdef MAIN
- char client[] = {0x0f, 0x02, 0x02, PIDMSB, PIDLSB, NODE};
- #else
- extern char client[];
- #endif
-
- #define PROTOCOL 0x5656
-
-
- #ifdef MAIN
- char myprotocol[] = {0x56, 0x56};
- #else
- extern char myprotocol[];
- #endif
-
-
- #ifdef MAIN
- char mynode[] = {0,0,0,0,0,0};
- #else
- extern char mynode[];
- #endif
-
- char *ipaddr(), *getenv();
-
- struct request {
- EI_PORT r_port; /* Ethernet header */
- int r_size; /* size of data field */
- char r_type; /* type of request */
- unsigned char r_sequence; /* Sequence number */
- char r_data[1024]; /* data field */
- };
-
- #define DATA 0 /* just data of some sort */
- #define UNDEFINED 1 /* crappy packet */
- #define REQUEST 2 /* Is this necessary? */
- #define TERMINATE 3 /* STOP! Exit ASAP */
- #define RMTSIGINT 4 /* signal from here to there */
- #define RMTSIGQUIT 5 /* another signal */
- #define ACCEPT 6 /* I accept that file */
- #define REJECT 7 /* I have rejected that file */
- #define PUTFILE 8 /* file to server */
- #define SENDFILE 9 /* file from server */
- SHAR_EOF
- if test 1591 -ne "`wc -c < 'ni.h'`"
- then
- echo shar: "error transmitting 'ni.h'" '(should have been 1591 characters)'
- fi
- fi
- echo shar: "extracting 'ftp.h'" '(192 characters)'
- if test -f 'ftp.h'
- then
- echo shar: "will not over-write existing file 'ftp.h'"
- else
- cat << \SHAR_EOF > 'ftp.h'
- /*
- * Some constants for the ftp
- */
- #define WINDOW 4 /* Window size */
- #define TRANSIT 2 /* Estimated transit time (sec) for window */
- #define MAXRETRY 5 /* No of timeouts per window */
-
-
- SHAR_EOF
- if test 192 -ne "`wc -c < 'ftp.h'`"
- then
- echo shar: "error transmitting 'ftp.h'" '(should have been 192 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-
- --
-
- Dave Settle,
- SMB Business Software, Thorn EMI Datasolve, High St, Mansfield, UK
-
- [Until 1 May] UUCP: dave@smb.co.uk
- ...!mcvax!ukc!nott-cs!smb!dave
-
-
- [After 1 May] UUCP: (to be announced ...)
-
-
- <--- This way to point of view --->
-
-